/**
  ******************************************************************************
  * @file    sccb.c
  * @author  W. Boerendans
  * @version V1.0.0
  * @date    24-november-2013
  * @brief   SCCB
  *         
  * <h2><center>&copy; COPYRIGHT 2013 W. Boerendans</center></h2>
  ******************************************************************************  
  */ 
	
/* Private includes ----------------------------------------------------------*/
#include "sccb.h"

/* Private declarations ------------------------------------------------------*/
/* Private prototypes --------------------------------------------------------*/
/* Functions -----------------------------------------------------------------*/
void sccbInit(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	I2C_InitTypeDef I2C_InitStructure;

	/* Clocks */
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	RCC_APB1PeriphClockCmd(SCCB_RCC_APBxPeriph, ENABLE);

	/* Init SCCB IO */
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_I2C2);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_I2C2);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	//don't use pull up here, but external resistors. Cam is not strong enough to pull down the lines.
	GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
	GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	/* Init I2C no. 2 */
	I2C_DeInit(SCCB_I2Cx);
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
	I2C_InitStructure.I2C_OwnAddress1 = 0x00;
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	I2C_InitStructure.I2C_ClockSpeed = SCCB_CAM_SPEED;
	I2C_Init(SCCB_I2Cx, &I2C_InitStructure);
	
	I2C_Cmd(SCCB_I2Cx, ENABLE);
}

uint8_t sccbWrite(uint8_t reg, uint8_t data)
{
  uint32_t timeout;
  uint32_t i = WRITE_DELAY;

  timeout = TIMEOUT_MAX;
  while(I2C_GetFlagStatus(SCCB_I2Cx, I2C_FLAG_BUSY))
  {
    if ((timeout--) == 0) return 0xFF;
  }

  // Start the config sequence
  I2C_GenerateSTART(SCCB_I2Cx, ENABLE);

  timeout = TIMEOUT_MAX;
  while (!I2C_CheckEvent(SCCB_I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
  {
    if ((timeout--) == 0) return 0xFF;
  }

  // Transmit the slave address and enable writing operation
  I2C_Send7bitAddress(SCCB_I2Cx, SCCB_CAM_WR_ADDRESS, I2C_Direction_Transmitter);

  // Test on EV6 and clear it
  timeout = TIMEOUT_MAX;
  while (!I2C_CheckEvent(SCCB_I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
  {
    if ((timeout--) == 0) return 0xFF;
  }

  I2C_SendData(SCCB_I2Cx, reg);

  // Test on EV8 and clear it
  timeout = TIMEOUT_MAX;
  while (!I2C_CheckEvent(SCCB_I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTING))
  {
    if ((timeout--) == 0) return 0xFF;
  }

  // Prepare the register value to be sent
  I2C_SendData(SCCB_I2Cx, data);

  // Wait till all data have been physically transferred on the bus
  timeout = TIMEOUT_MAX;
  while (!I2C_CheckEvent(SCCB_I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
  {
    if ((timeout--) == 0) return 0xFF;
  }

  // End the configuration sequence
  I2C_GenerateSTOP(SCCB_I2Cx, ENABLE);

  // Short delay
  // It seems like the chip needs some time to perform a write operation
  while(i!=0)
    i--;
		
	return 0;
}

uint8_t sccbRead(uint8_t reg)
{
  uint8_t result = 0;
  uint32_t timeout;

	/* Test on BUSY Flag */
  timeout = TIMEOUT_MAX;
  while(I2C_GetFlagStatus(SCCB_I2Cx, I2C_FLAG_BUSY))
  {
    if ((timeout--) == 0) return 0xFF;
  }

  // Start the config sequence
  I2C_GenerateSTART(SCCB_I2Cx, ENABLE);

  timeout = TIMEOUT_MAX;
  while (!I2C_CheckEvent(SCCB_I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
  {
    if ((timeout--) == 0){
			return 0xFF;
		}
  }

  // Transmit the slave address and enable writing operation
  I2C_Send7bitAddress(SCCB_I2Cx, SCCB_CAM_RD_ADDRESS, I2C_Direction_Transmitter);

  // Test on EV6 and clear it
  timeout = TIMEOUT_MAX;
  while (!I2C_CheckEvent(SCCB_I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
  {
    if ((timeout--) == 0){
			return 0xFF;
		}
  }

  I2C_SendData(SCCB_I2Cx, reg);

  // Test on EV8 and clear it
  timeout = TIMEOUT_MAX;
  while (!I2C_CheckEvent(SCCB_I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
  {
    if ((timeout--) == 0){
			return 0xFF;
		}
  }

  // End the configuration sequence
  I2C_GenerateSTOP(SCCB_I2Cx, ENABLE);

  timeout = TIMEOUT_MAX;
  while(I2C_GetFlagStatus(SCCB_I2Cx, I2C_FLAG_BUSY))
  {
    if ((timeout--) == 0){
			return 0xFF;
		}
  }

  // Send START condition a second time
  I2C_GenerateSTART(SCCB_I2Cx, ENABLE);

  // Test on EV5 and clear it (cleared by reading SR1 then writing to DR)
  timeout = TIMEOUT_MAX;
  while(!I2C_CheckEvent(SCCB_I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
  {
    if ((timeout--) == 0) return 0xFF;
  }

  // Send Codec address for read
  I2C_Send7bitAddress(SCCB_I2Cx, SCCB_CAM_RD_ADDRESS, I2C_Direction_Receiver);

  // Wait on ADDR flag to be set (ADDR is still not cleared at this level
  timeout = TIMEOUT_MAX;
  while(!I2C_CheckEvent(SCCB_I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
  {
    if ((timeout--) == 0) return 0xFF;
  }

  // Disable Acknowledgment
  I2C_AcknowledgeConfig(SCCB_I2Cx, DISABLE);

  // Send STOP Condition
  I2C_GenerateSTOP(SCCB_I2Cx, ENABLE);

  // Wait for the byte to be received
  timeout = TIMEOUT_MAX;
  while(!I2C_CheckEvent(SCCB_I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED))
  {
    if ((timeout--) == 0) return 0xFF;
  }

  // Read the byte received from the Codec
  result = I2C_ReceiveData(SCCB_I2Cx);

  // Re-Enable Acknowledgment to be ready for another reception
  I2C_AcknowledgeConfig(SCCB_I2Cx, ENABLE);

  // Clear AF flag for next communication
  I2C_ClearFlag(SCCB_I2Cx, I2C_FLAG_AF);

  return result;
}
